package com.chenfan.process.util;

import com.alibaba.fastjson.JSONObject;
import com.chenfan.ccp.common.exception.ApiException;
import com.chenfan.ccp.util.tool.JsonUtil;
import com.chenfan.process.common.exception.ProcessResultCode;
import com.chenfan.process.entity.po.ProcessRelatedAttribute;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liuming
 * @date 2022/1/7
 */
public class CalculateUtil {

    /**
     * 关联关系 0-小于 1-小于等于 2-等于 3-大于 4-大于等于 5-不等于 计算条件分支
     * @return
     */
    public static JSONObject checkField(List<ProcessRelatedAttribute> processRelatedAttributeList, String parameter) {
        JSONObject jsonObject = JsonUtil.string2Obj(parameter, JSONObject.class);
        if (jsonObject == null) {
            throw new ApiException(ProcessResultCode.JSON_FORMAT_ERROR);
        }
        boolean match = processRelatedAttributeList.stream().allMatch(e -> jsonObject.containsKey(e.getRelatedKey()));
        if (!match) {
            throw new ApiException(ProcessResultCode.PARAMETER_ERROR);
        }
        return jsonObject;
    }

    public static boolean calculate(ProcessRelatedAttribute attribute, String value) {
        List<String> dataList = parseData(attribute.getRelatedValue());

        if (MathUtil.isNumeric(value)) {
            switch (attribute.getRelatedType()) {
                case 0:
                    return new BigDecimal(value).compareTo(new BigDecimal(attribute.getRelatedValue())) < 0;
                case 1:
                    return new BigDecimal(value).compareTo(new BigDecimal(attribute.getRelatedValue())) <= 0;
                case 2:
                    return dataList.stream().anyMatch(data -> new BigDecimal(value).compareTo(new BigDecimal(data)) == 0);
                case 3:
                    return new BigDecimal(value).compareTo(new BigDecimal(attribute.getRelatedValue())) > 0;
                case 4:
                    return new BigDecimal(value).compareTo(new BigDecimal(attribute.getRelatedValue())) >= 0;
                case 5:
                    return dataList.stream().noneMatch(data -> new BigDecimal(value).compareTo(new BigDecimal(data)) == 0);
                default:
                    return false;
            }
        } else {
            switch (attribute.getRelatedType()) {
                case 2:
                    return dataList.stream().anyMatch(data -> Objects.equals(value, data));
                case 5:
                    return dataList.stream().noneMatch(data -> Objects.equals(value, data));
                default:
                    throw new ApiException(ProcessResultCode.FORMATTER_ERROR);
            }
        }
    }

    public static List<String> parseData(String data) {
        if (StringUtils.isEmpty(data)) {
            return Collections.emptyList();
        }
        try {
            return JSONObject.parseArray(data, String.class);
        } catch (Exception e) {
            return Collections.singletonList(data);
        }
    }

    public static boolean match(List<ProcessRelatedAttribute> processRelatedAttributeList, JSONObject jsonObject) {
        // 取出所有的数据进行计算. 看是否有满足的场景, 先根据Group进行分组. 只要满足任意一个组即可返回True

        Map<Long, List<ProcessRelatedAttribute>> groupMap = processRelatedAttributeList.stream().collect(Collectors.groupingBy(ProcessRelatedAttribute::getGroupId));
        return groupMap.entrySet().stream().anyMatch(e -> {
            List<ProcessRelatedAttribute> value = e.getValue();
            // 每个小group进行计算. 先看看小组中是否有或的条件
            List<ProcessRelatedAttribute> orAttributeList = value.stream().filter(ProcessRelatedAttribute::or).collect(Collectors.toList());
            List<ProcessRelatedAttribute> andAttributeList = value.stream().filter(ProcessRelatedAttribute::and).collect(Collectors.toList());
            boolean match = false;
            // 如果有或的条件分支, 先计算或的逻辑
            if (!CollectionUtils.isEmpty(orAttributeList)) {
                match = orAttributeList.stream().anyMatch(o -> calculate(o, jsonObject.getString(o.getRelatedKey())));
                if (match) {
                    return true;
                }
            }

            if (!CollectionUtils.isEmpty(andAttributeList)) {
                match = andAttributeList.stream().allMatch(o -> calculate(o, jsonObject.getString(o.getRelatedKey())));
            }
            return match;
        });
    }
}
